package com.ruoyi.web.controller.file;

import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.common.utils.file.MimeTypeUtils;
import com.ruoyi.common.utils.uuid.Seq;
import org.apache.commons.io.FilenameUtils;
import org.apache.tika.Tika;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

/**
 * oss 文件上传
 *
 * @author fengcheng
 */
@RestController
@RequestMapping("/file")
public class FileDetailController {

    private static final Logger log = LoggerFactory.getLogger(FileDetailController.class);

    @Autowired
    private FileStorageService fileStorageService;

    /**
     * 上传图片，成功返回文件 url
     *
     * @param file 文件
     * @return
     */
    @PostMapping("/uploadImage")
    public AjaxResult uploadImage(MultipartFile file) throws IOException {
        if (file.isEmpty()) {
            throw new RuntimeException("请上传文件!");
        }
        Tika tika = new Tika();
        String mimeType = tika.detect(file.getInputStream());

        // 检查是否允许MIME类型
        if (!isValidMimeType(mimeType, false)) {
            throw new RuntimeException("文件类型不合法!");
        }

        return returntResult(file);
    }

    /**
     * 上传文件，成功返回文件 url
     *
     * @param file 文件
     * @return
     */
    @PostMapping("/upload")
    public AjaxResult upload(MultipartFile file) throws IOException {
        if (file.isEmpty()) {
            throw new RuntimeException("请上传文件!");
        }
        Tika tika = new Tika();
        String mimeType = tika.detect(file.getInputStream());

        // 检查是否允许MIME类型
        if (!isValidMimeType(mimeType, true)) {
            throw new RuntimeException("文件类型不合法!");
        }

        return returntResult(file);
    }


    /**
     * 下载请求
     */
    @PostMapping("/download")
    public void fileDownload(HttpServletResponse response, HttpServletRequest request) {
        try {
            FileInfo fileInfo = getFileInfo(request);
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            FileUtils.setAttachmentResponseHeader(response, fileInfo.getFilename());
            fileStorageService.download(fileInfo).outputStream(response.getOutputStream());
        } catch (IOException e) {
            log.error("下载文件失败", e);
        }
    }

    /**
     * 文件删除
     */
    @PostMapping("/delete")
    public AjaxResult fileDelete(HttpServletRequest request) {
        //直接删除
        fileStorageService.delete(getFileInfo(request));
        return AjaxResult.success();
    }

    /**
     * 成功返回文件
     *
     * @param file
     * @return
     */
    private AjaxResult returntResult(MultipartFile file) {
        FileInfo fileInfo = fileStorageService.of(file)
                .setPath(DateUtils.datePath() + "/")
                .setSaveFilename(extractFilename(file))
                .upload();

        AjaxResult ajax = AjaxResult.success();
        ajax.put("url", fileInfo.getUrl());
        ajax.put("fileName", "/file/" + DateUtils.datePath() + "/" + extractFilename(file));
        ajax.put("newFileName", fileInfo.getFilename());
        ajax.put("originalFilename", file.getOriginalFilename());
        return ajax;
    }

    /**
     * 获取文件信息
     *
     * @param request
     * @return
     */
    private FileInfo getFileInfo(HttpServletRequest request) {
        String fileUrl = request.getParameter("fileUrl");
        if (StringUtils.isEmpty(fileUrl)) {
            throw new RuntimeException("fileUrl 不能为空");
        }
        FileInfo fileInfo = fileStorageService.getFileInfoByUrl(fileUrl);

        //判断文件是否存在
        if (!fileStorageService.exists(fileInfo)) {
            throw new RuntimeException("文件不存在");
        }
        return fileInfo;
    }

    /**
     * 编码文件名
     */
    private static String extractFilename(MultipartFile file) {
        return StringUtils.format("{}_{}.{}",
                FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));
    }

    /**
     * 获取文件名的后缀
     *
     * @param file 表单文件
     * @return 后缀名
     */
    private static String getExtension(MultipartFile file) {
        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
        if (StringUtils.isEmpty(extension)) {
            extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));
        }
        return extension;
    }

    /**
     * 文件验证 isAll true 全部验证  false 只验证图片
     *
     * @param mimeType
     * @param isAll
     * @return
     */
    private boolean isValidMimeType(String mimeType, boolean isAll) {
        if (isAll) {
            // 允许的MIME类型列表
            String[] allowedMimeTypes = {"image/png", "image/jpeg", "image/gif", "application/zip", "text/plain", "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/pdf", "application/x-rar-compressed"};

            for (String allowedMimeType : allowedMimeTypes) {
                if (allowedMimeType.equalsIgnoreCase(mimeType)) {
                    return true;
                }
            }
            return false;

        } else {
            // 允许的MIME类型列表
            String[] allowedMimeTypes = {"image/png", "image/jpeg", "image/gif"};
            for (String allowedMimeType : allowedMimeTypes) {
                if (allowedMimeType.equalsIgnoreCase(mimeType)) {
                    return true;
                }
            }
            return false;
        }

    }
}
